package com.spa.domain.entity;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.json.JSONUtil;
import com.spa.application.command.common.rule.RuleAddCommand;
import com.spa.application.dto.common.rule.KpiDto;
import com.spa.application.dto.common.rule.RuleDto;
import com.spa.infrastructure.enums.dict.rule.RuleClassifyEnum;
import com.spa.infrastructure.enums.dict.rule.RuleFlagEnum;
import com.spa.infrastructure.enums.dict.rule.RuleKpiConditionEnum;
import com.spa.infrastructure.enums.dict.rule.RuleKpiEnum;
import com.spa.infrastructure.enums.dict.rule.RuleTypeEnum;
import com.spa.infrastructure.exception.SpaException;
import com.spa.infrastructure.util.CurrencyUtils;
import com.spa.infrastructure.util.StringUtils;
import lombok.Data;
import lombok.ToString;

import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;

/**
 * 规则
 */
@Data
@ToString
public class Rule {

    /**
     * 相关ID
     */
    private Long relevanceId;

    /**
     * 序号
     */
    private Integer serial;

    /**
     * 类型（10 固定规则，20 浮动规则）
     */
    private Integer type;

    /**
     * 标识（10 订单，20 加钟订单 ）
     */
    private Integer flag;
    /**
     * 分组 10 技师 20 门店）
     */
    private Integer classify;

    /**
     * 值
     */
    private String val;

    /**
     * 表达式
     */
    private String expression;


    public static List<RuleDto> listRuleToDto(List<Rule> ruleList) {
        List<RuleDto> ruleDtoList = new ArrayList<>();
        if (CollUtil.isEmpty(ruleList)) {
            return ruleDtoList;
        }
        ruleList.stream().forEach(a -> {
            RuleDto ruleDto = new RuleDto();
            ruleDto.setRuleTypeEnum(RuleTypeEnum.byCode(a.getType()));
            ruleDto.setRuleTypeDesc(ruleDto.getRuleTypeEnum().getDesc());
            ruleDto.setRuleFlagEnum(RuleFlagEnum.byCode(a.getFlag()));
            ruleDto.setRuleFlagDesc(ruleDto.getRuleFlagEnum().getDesc());
            ruleDto.setRuleClassifyEnum(RuleClassifyEnum.byCode(a.getClassify()));
            ruleDto.setRuleClassifyDesc(ruleDto.getRuleClassifyEnum().getDesc());
            ruleDto.setVal(a.getVal());
            ruleDto.setSerial(a.getSerial());

            ruleDto.setFlag(ruleDto.getRuleFlagEnum().getCode());
            ruleDto.setType(ruleDto.getRuleTypeEnum().getCode());

            List<KpiDto> kpiList = new ArrayList<>();
            if (StringUtils.isNotEmpty(a.getExpression())) {
                kpiList = JSONUtil.toList(a.getExpression(), KpiDto.class);
            }
            ruleDto.setKpiList(kpiList);

            ruleDtoList.add(ruleDto);

        });
        return ruleDtoList;

    }

    public static List<RuleDto> listRuleParamToDto(List<RuleAddCommand> ruleParamList, RuleClassifyEnum ruleClassifyEnum) {
        List<RuleDto> ruleDtoList = new ArrayList<>();
        if (CollUtil.isEmpty(ruleParamList)) {
            return ruleDtoList;
        }

        ruleParamList.stream().forEach(a -> {
            RuleDto ruleDto = new RuleDto();
            ruleDto.setRuleTypeEnum(RuleTypeEnum.byCode(a.getType()));
            ruleDto.setRuleTypeDesc(ruleDto.getRuleTypeEnum().getDesc());
            ruleDto.setRuleFlagEnum(RuleFlagEnum.byCode(a.getFlag()));
            ruleDto.setRuleFlagDesc(ruleDto.getRuleFlagEnum().getDesc());
            ruleDto.setRuleClassifyEnum(ruleClassifyEnum);
            ruleDto.setRuleClassifyDesc(ruleDto.getRuleClassifyEnum().getDesc());
            ruleDto.setVal(a.getVal());
            ruleDto.setSerial(a.getSerial());

            List<KpiDto> kpiList = new ArrayList<>();
            if (StringUtils.isNotEmpty(a.getKpiList())) {
                BeanUtil.copyProperties(a.getKpiList(), kpiList);
            }
            ruleDto.setKpiList(kpiList);

            ruleDtoList.add(ruleDto);

        });
        return ruleDtoList;

    }


    public static List<KpiDto> expressionToDtoList(String expression) {

        List<KpiDto> kpiDtoList = new ArrayList<>();
        if (StringUtils.isEmpty(expression)) {
            return kpiDtoList;
        }
        kpiDtoList = JSONUtil.toList(expression, KpiDto.class);

        if (CollUtil.isNotEmpty(kpiDtoList)) {
            return kpiDtoList.stream().sorted(Comparator.comparing(KpiDto::getSerial)).toList();
        }
        return kpiDtoList;

    }

    /**
     * 规则列表转文字描述
     *
     * @author: lig
     * @date: 2024/4/9
     */
    public static String ruleDtoListToStr(List<RuleDto> ruleDtoList) {
        if (CollUtil.isEmpty(ruleDtoList)) {
            return "";
        }
        StringBuffer strBuffer = new StringBuffer();

        String orderStr = "%s%s：%s%s比例 %s%s ";
        String orderRuleKpiStr = "%s%s%s%s：%s %s %s%s ";

        List<RuleDto> orderRuleList = ruleDtoList.stream().filter(f1 -> RuleFlagEnum.$10.equals(f1.getRuleFlagEnum())).sorted(Comparator.comparing(RuleDto::getSerial)).toList();
        DecimalFormat df = new DecimalFormat("0.00");
        if (CollUtil.isNotEmpty(orderRuleList)) {
            orderRuleList.stream().forEach(o1 -> {
                String str = String.format(orderStr, "订单规则", o1.getSerial(), o1.getRuleClassifyEnum().getDesc(), o1.getRuleTypeEnum().getDesc(), df.format(Convert.toDouble(o1.getVal(), 0d) * 100), "%");
                strBuffer.append("\n");
                strBuffer.append(str);

                List<KpiDto> kpiList = o1.getKpiList();
                if (CollUtil.isNotEmpty(kpiList)) {
                    kpiList = kpiList.stream().sorted(Comparator.comparing(KpiDto::getSerial)).toList();

                    kpiList.stream().forEach(k1 -> {
                        String unit = "元";
                        String kpiVal = k1.getKpiVal();
                        if (!RuleKpiEnum.$10.getDesc().equals(k1.getKpiKey())) {
                            kpiVal = "" + df.format(Convert.toDouble(k1.getKpiVal(), 0d) * 100);
                            unit = "%";
                        }else {
                            kpiVal = CurrencyUtils.fenToYuan(Convert.toInt(kpiVal)).toString();
                        }
                        String kpiStr = String.format(orderRuleKpiStr, "订单规则", o1.getSerial(), "指标", k1.getSerial(), k1.getKpiKey(), RuleKpiConditionEnum.byCode(k1.getCondition()).getDesc(), kpiVal, unit);
                        strBuffer.append("\n");
                        strBuffer.append(kpiStr);

                    });
                }
            });
        }

        //加钟
        List<RuleDto> orderExtRuleList = ruleDtoList.stream().filter(f1 -> RuleFlagEnum.$20.equals(f1.getRuleFlagEnum())).sorted(Comparator.comparing(RuleDto::getSerial)).toList();
        if (CollUtil.isNotEmpty(orderExtRuleList)) {
            strBuffer.append("\n");
            strBuffer.append("----------------");
            //orderExtStr.append("加钟订单规则：");
            orderExtRuleList.stream().forEach(o2 -> {

                String str = String.format(orderStr, "加钟订单规则", o2.getSerial(), o2.getRuleClassifyEnum().getDesc(), o2.getRuleTypeEnum().getDesc(), Convert.toDouble(o2.getVal(), 0d) * 100, "%");
                strBuffer.append("\n");
                strBuffer.append(str);
            });

        }

        return strBuffer.toString();

    }

    /**
     * 校验规则阈值
     *
     * @param ruleBoundaryList 规则阈值list
     * @param ruleDtoList      校验的规则list
     * @author: lig
     * @date: 2024/4/10
     */
    public static void verifyBoundary(List<RuleDto> ruleBoundaryList, List<RuleDto> ruleDtoList) {
        if (CollUtil.isNotEmpty(ruleBoundaryList) && CollUtil.isNotEmpty(ruleDtoList)) {
            List<RuleDto> ruleOrderList1 = ruleBoundaryList.stream().filter(f1 -> RuleFlagEnum.$10.equals(f1.getRuleFlagEnum())).toList();
            List<RuleDto> ruleOrderExtList1 = ruleBoundaryList.stream().filter(f1 -> RuleFlagEnum.$20.equals(f1.getRuleFlagEnum())).toList();

            List<RuleDto> ruleOrderList2 = ruleDtoList.stream().filter(f1 -> RuleFlagEnum.$10.equals(f1.getRuleFlagEnum())).toList();
            List<RuleDto> ruleOrderExtList2 = ruleDtoList.stream().filter(f1 -> RuleFlagEnum.$20.equals(f1.getRuleFlagEnum())).toList();

            //订单 固定规则比较
            compareRule(ruleOrderList1, ruleOrderList2, RuleTypeEnum.$10);

            //订单 浮动规则比较
            compareRule(ruleOrderList1, ruleOrderList2, RuleTypeEnum.$20);

            //加钟订单 浮动规则比较
            compareRule(ruleOrderExtList1, ruleOrderExtList2, RuleTypeEnum.$20);


        }

    }

    public static void compareRule(List<RuleDto> ruleOrderList1, List<RuleDto> ruleOrderList2, RuleTypeEnum ruleTypeEnum) {

        List<RuleDto> fixedList1 = ruleOrderList1.stream().filter(f1 -> ruleTypeEnum.equals(f1.getRuleTypeEnum())).sorted(Comparator.comparing(RuleDto::getSerial)).toList();
        List<RuleDto> fixedList2 = ruleOrderList2.stream().filter(f1 -> ruleTypeEnum.equals(f1.getRuleTypeEnum())).sorted(Comparator.comparing(RuleDto::getSerial)).toList();

        if (CollUtil.isNotEmpty(fixedList1) && CollUtil.isNotEmpty(fixedList2)) {
            ////获取默认值
            //RuleDto defaultRuleDto = fixedList1.get(0);
            RuleDto ruleDto1 = null;

            for (int i = 0; i < fixedList2.size(); i++) {
                if (i < fixedList1.size()) {
                    ruleDto1 = fixedList1.get(i);
                }
                RuleDto ruleDto2 = fixedList2.get(i);

                //固定规则比较
                if (Convert.toDouble(ruleDto2.getVal(), 0d) > Convert.toDouble(ruleDto1.getVal(), 0d)) {
                    //XX 订单 固定规则 值 不能超过 XX 订单 固定规则 值
                    String msg = String.format("%s%s%s %s，不能超过，%s%s%s %s",
                            ruleDto2.getRuleClassifyDesc(),
                            ruleDto2.getRuleFlagDesc(),
                            ruleDto2.getRuleTypeDesc(),
                            Convert.toDouble(ruleDto2.getVal()) * 100,
                            ruleDto1.getRuleClassifyDesc(),
                            ruleDto1.getRuleFlagDesc(),
                            ruleDto1.getRuleTypeDesc(),
                            Convert.toDouble(ruleDto1.getVal()) * 100);
                    throw new SpaException(msg);
                }

            }

        }
    }

    /**
     * 指标信息
     *
     * @author: lig
     * @date: 2024/3/28
     */
    @Data
    public static class KpiInfo {

        /**
         * 业绩
         */
        private Integer perf;

        /**
         * 加钟率
         */
        private Double extraRatio;

        /**
         * 好评率
         */
        private Double positiveRatio;


    }

}